window.NXSTdata = window.NXSTdata || {};
window.NXSTdata.content = window.NXSTdata.content || {};
window.NXSTdata.page = window.NXSTdata.page || {};
window.NXSTdata.site = window.NXSTdata.site || {};
window.NXSTdata.ads = window.NXSTdata.ads || {};
window.NXSTdata.layout = window.NXSTdata.layout || {};
window.NXSTdata.privacy = window.NXSTdata.privacy || {};
window.NXSTdata.alerts = window.NXSTdata.alerts || {};
window.NXSTdata.location = window.NXSTdata.location || {};

populateNXSTData()

document.addEventListener('DOMContentLoaded', (event) => {
  if (window.NXSTdata.content.title === '') {
    window.NXSTdata.content.title = document.title;
  }

  window.NXSTdata.content.videoPlayerTypes = []

  addVideoPlayer('div.s2nFriendlyFrame', 'sendtonews')
  addVideoPlayer('div.s2nPlayer', 'sendtonews')
  addVideoPlayer('div.fb-video', 'facebook')
  addVideoPlayer('iframe[src*="youtube.com"]', 'youtube')
  addVideoPlayer('iframe[src*="venn.tv"], iframe[src*="https://venn-dev"]', 'venn')
  addVideoPlayer('div[data-react-component="VideoPlayer"]', 'videojs')
  addVideoPlayer('div[data-react-component="AnvatoVideoPlayer"]', 'akta')
  /* Custom event to signal UDL data has been fully loaded. */
  document.dispatchEvent( new CustomEvent( 'UniversalDataLayerLoaded' ) )
})

function addVideoPlayer(selector, name) {

  const videoCount = document.querySelectorAll(selector).length
  if(videoCount) {
    window.NXSTdata.content.videoPlayerTypes.push(name)
    if ('akta' !== name && 'videojs' !== name)  {
        window.NXSTdata.content.videoCount += videoCount
    }
  }
}

function uuid4() {
    /* Generetes a UUID (Version 4) per RFC 4122 using crypto API. */
    return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
        (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
    )
}

function populatePage() {
    /* Define query parameter fetching function. */
    const getQueryParams = () => {
        /* Define value parsing function. */
        const parseValue = (value) => {
            try {
                return JSON.parse(value)
            }
            catch (error) {
                return value
            }
        }
        /* Read parameters. */
        const search = window.location.search || ''
        const params = new URLSearchParams(search.startsWith('?') ? search : `?${search}`)
        /* Parse and return parameters. */
        return [...params.entries()].reduce(
            (obj, [key, value]) => ({
                ...obj,
                [key]: (
                    obj.hasOwnProperty(key)
                    /* Convert existing key to array, or append to array. */
                    ? [...(Array.isArray(obj[key]) ? obj[key] : [obj[key]]), (parseValue(value))]
                    /* Add parsed value. */
                    : (parseValue(value))
                )
            }), {}
        )
    }
    /* Create and assign a unique ID. */
    window.NXSTdata.page.uniqueId = uuid4()
    /* Assign values. */
    window.NXSTdata.page.fullUrl = window.document.location.href || ""
    window.NXSTdata.page.queryParams = getQueryParams() || {}
    window.NXSTdata.page.urlHash = window.document.location.hash || ""
    window.NXSTdata.page.referrer = (
        (window.NXSTdata.page.queryParams.referrer || window.NXSTdata.page.queryParams.referrer === "")
        ? window.NXSTdata.page.queryParams.referrer
        : document.referrer
    )
}

function populateAdSlots() {
    /* Define ad slot fetching function. */
    const getAdSlots = () => (window.googletag.pubads().getSlots().map((slot) => (slot.getTargeting('pos')[0])) || [])
    /* Proceed if GPT is up. */
    if (window.googletag && googletag.pubadsReady) {
        /* Fetch slots. */
        window.NXSTdata.ads.adSlots = getAdSlots()
        /* Register event listener for future slot requests. */
        window.googletag.pubads().addEventListener('slotRequested', (event) => {
            window.NXSTdata.ads.adSlots = getAdSlots()
        })
    }
    else {
        /* Assign a value if previously did not assigned. */
        window.NXSTdata.ads.adSlots = window.NXSTdata.ads.adSlots || []
        /* Poll GPT until available. */
        setTimeout(populateAdSlots, 100)
    }
}

function populatePrivacy() {
    /* Assign default values. */
    window.NXSTdata.privacy = {
        activeRules: [],
        usPrivacyString: '',
        gppString: '',
        essentialCookies: true,
        limitNexstar: false,
        limitOthers: false,
        consentCookieSetDate: '',
        ccpaAlertClosed: false,
        __cookie_check: 10, // Control variable
        saleOfPersonalData: '',
        oneTrustActiveGroups: '',
        ...window.NXSTdata.privacy,
    }
    /* Determine if CCPA is active. */
    if (window.__inScopeForCCPA && !window.NXSTdata.privacy.activeRules.includes('ccpa')) {
        window.NXSTdata.privacy.activeRules.push('ccpa')
        /* Sort to normalize order. */
        window.NXSTdata.privacy.activeRules.sort()
    }
    /* Create control variables for cookie checks. */
    const must_cookies = [
        'usprivacy',
        'OTGPPConsent',
        'ConsentCookies',
        'CookieSetDate',
        'AlertBanner',
        'nxst_id',
        'OptanonConsent'
    ]
    let should_check = must_cookies.length
    const check_limit_reached = (window.NXSTdata.privacy.__cookie_check <= 0)
    /* Fetch cookies. */
    const cookies = document.cookie
    /* Traverse cookies. */
    cookies.split(';').map((item) => {
        /* Fetch key - value pair. */
        const [ key, ...val_arr ] = item.trim().split('=')
        const value = val_arr.join('=')
        /* Adjust control variables. */
        if (must_cookies.includes(key)) {
            should_check = should_check - 1
        }
        /* Act based on key. */
        if (key === 'usprivacy') {
            /* Assign string value. */
            window.NXSTdata.privacy.usPrivacyString = value
        }
        else if (key === 'OTGPPConsent') {
            window.NXSTdata.privacy.gppString = value
        }
        else if (key === 'ConsentCookies') {
            /* Parse stored JSON. */
            const {
                strictly_necessary=window.NXSTdata.privacy.essentialCookies,
                block_nexstar=window.NXSTdata.privacy.limitNexstar,
                block_others=window.NXSTdata.privacy.limitOthers
            } = JSON.parse(value)
            /* Assign boolean values. */
            window.NXSTdata.privacy.essentialCookies = !!strictly_necessary
            window.NXSTdata.privacy.limitNexstar = !!block_nexstar
            window.NXSTdata.privacy.limitOthers = !!block_others
        }
        else if (key === 'CookieSetDate') {
            /* Parse date into array of strings with padding. */
            const numberStringList = value.match(/\d+/g).map((item, index) => (
                item.toString(10).padStart(index === 0 ? 4 : 2, '0')
            ))
            /* Assign string value. */
            window.NXSTdata.privacy.consentCookieSetDate = numberStringList.join('-')
        }
        else if (key === 'AlertBanner') {
            /* Assign string value. */
            window.NXSTdata.privacy.ccpaAlertClosed = (value === 'closed')
        }
        else if (key === 'nxst_id') {
            /* Ensure uniqueness. */
            if (!window.NXSTdata.privacy.activeRules.includes('nexstarid')) {
                /* Add Nexstar ID to active rules. */
                window.NXSTdata.privacy.activeRules.push('nexstarid')
                /* Sort to normalize order. */
                window.NXSTdata.privacy.activeRules.sort()
            }
        }
        else if (key === 'OptanonConsent') {
          let groups = []
          decodeURIComponent(value).split('&').map((i) => {
            const [ k, ...val_arr ] = i.trim().split('=')
            const value = val_arr.join('=')
              if( k == 'groups'){
                groups = value.split(",").map((group) => { return group.split(':') })
              }
          })
          const activeGroups = groups.filter((group) => { return Boolean(parseInt(group[group.length-1])) })
          window.NXSTdata.privacy.saleOfPersonalData = Boolean(groups.find((group) => {
            const key = group[0] || ''
            const value = Boolean(parseInt(group[1]))
            if ( key ===  "SPD_BG" ) {
                return value
            }
          }))
          window.NXSTdata.privacy.oneTrustActiveGroups = activeGroups.map((group) => { return group[0] }).join(',')
      }
    })
    /* Register repeated function call if it fired too early. */
    if (should_check && !check_limit_reached) {
        /* Update stored control variable. */
        window.NXSTdata.privacy.__cookie_check = window.NXSTdata.privacy.__cookie_check - 1
        /* Schedule function call. */
        window.setTimeout(populatePrivacy, 100)
    }
    else {
        /* Remove stored control variable. */
        delete window.NXSTdata.privacy.__cookie_check
    }
}

function populateIdentity() {
    /* Assign default values. */
    window.NXSTdata.identity = {
        gaClientId: '',
        blueconicId: '',
        nexstarId: '',
        segmentUserId: '',
        __cookie_check: 10, // Control variable
        ...window.NXSTdata.identity
    }
    /* Create control variables for cookie checks. */
    const must_cookies = [
        'BCSessionID',
        '_ga',
    ]
    let should_check = must_cookies.length
    const check_limit_reached = (window.NXSTdata.identity.__cookie_check <= 0)
    /* Fetch cookies. */
    const cookies = document.cookie
    /* Traverse cookies. */
    cookies.split(';').map((item) => {
        /* Fetch key - value pair. */
        const [ key, ...val_arr ] = item.trim().split('=')
        const value = val_arr.join('=')
        /* Adjust control variables. */
        if (must_cookies.includes(key)) {
            should_check = should_check - 1
        }
        /* Act based on key. */
        if (key === 'BCSessionID') {
            /* Assign string value. */
            window.NXSTdata.identity.blueconicId = value
        }
        else if (key === '_ga') {
            /* Assign string value. */
            window.NXSTdata.identity.gaClientId = value.split('.').splice(2).join('.')
        }
        else if (key === 'nxst_id') {
            /* Assign string value. */
            window.NXSTdata.identity.nexstarId = value
        }
    })

    /* Try to assign SegmentID as NexstarID. If not available, fallback to BlueConicID. */
    window.NXSTdata.identity.segmentUserId = (
        window.NXSTdata.identity.nexstarId
        || window.NXSTdata.identity.blueconicId
    )

    /* Register repeated function call if it fired too early. */
    if (should_check && !check_limit_reached) {
        /* Update stored control variable. */
        window.NXSTdata.identity.__cookie_check = window.NXSTdata.identity.__cookie_check - 1
        /* Schedule function call. */
        window.setTimeout(populateIdentity, 100)
    }
    else {
        /* Remove stored control variable. */
        delete window.NXSTdata.identity.__cookie_check
    }

    /* As requested on WC-1709. If we have the toggle `blueconic_deprioritization`
       on, we should use the ndn cookie for the nexstarId. */
    if(document.getElementById("blueconic_deprioritization")) {
        window.NXSTdata.identity.nexstarId = window.zzz_ndn;
    }
}

function setPermutiveGeoDataInUDL() {
  const permutiveDataEnrichersName = 'permutive-data-enrichers'
  // try to get permutive data enrichers from localStorage
  const localPermutiveDataEnrichers = localStorage.getItem(
    permutiveDataEnrichersName
  )
  // if data is already on the localStorage just run the handler else hook it
  if (localPermutiveDataEnrichers) {
    setItemHandler(permutiveDataEnrichersName, localPermutiveDataEnrichers)
  } else {
    // hook into localStorage and set permutive data enricher on the UDL
    hookInto(localStorage, 'setItem', setItemHandler)
  }
  // handler for permutive's data enrichers
  function setItemHandler(key, value) {
    if (key !== permutiveDataEnrichersName) {
      return
    }

    // get data from local storage
    const { data = {} } = JSON.parse(value)["enricher:geoip"];
    // store data into the UDL
    NXSTdata.location.geoCity = data.geo_info.city || '';
    NXSTdata.location.geoContinent = data.geo_info.continent || '';
    NXSTdata.location.geoCountry = data.geo_info.country || '';
    NXSTdata.location.geoRegion = data.geo_info.province || '';
    NXSTdata.location.isp = data.isp_info.isp || '';
    NXSTdata.location.ispOrganization = data.isp_info.organization || '';
  }
  /**
   * hookInto
   *
   * This will hook into a function of an object so we can check the arguments
   * used when it is called any time and do some calculations on those arguments.
   *
   * @param {object} targetObject Object where the function is function is
   * @param {string} functionName The name of the function you want to target
   * @param {function} handler The hook function that will handle the arguments
   * @returns {undefined}
   */
  function hookInto(targetObject, functionName, handler = () => {}) {
    // save the original function
    const backupFunction = targetObject[functionName]
    // overwrite the original function and set the handler
    targetObject[functionName] = function(...args) {
      // handle the arguments with the custom handler
      handler(...args)
      // trigger the original function as normal
      backupFunction.apply(targetObject, args)
    }
  }
}

/* Populates all layer data */
function populateNXSTData() {
    /* Call populate functions for NXSTData */
    populatePage()
    populateAdSlots()
    populatePrivacy()
    populateIdentity()
    setPermutiveGeoDataInUDL()
}